// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef V8_COMPILER_OPERATION_TYPER_H_
#define V8_COMPILER_OPERATION_TYPER_H_

#include "src/base/flags.h"
#include "src/compiler/opcodes.h"
#include "src/compiler/types.h"
#include "src/objects.h"

namespace v8 {
namespace internal {

    // Forward declarations.
    class Isolate;
    class RangeType;
    class Zone;

    namespace compiler {

        // Forward declarations.
        class Operator;
        class Type;
        class TypeCache;

        class V8_EXPORT_PRIVATE OperationTyper {
        public:
            OperationTyper(JSHeapBroker* broker, Zone* zone);

            // Typing Phi.
            Type Merge(Type left, Type right);

            Type ToPrimitive(Type type);
            Type ToNumber(Type type);
            Type ToNumberConvertBigInt(Type type);
            Type ToNumeric(Type type);
            Type ToBoolean(Type type);

            Type WeakenRange(Type current_range, Type previous_range);

// Unary operators.
#define DECLARE_METHOD(Name) Type Name(Type type);
            SIMPLIFIED_NUMBER_UNOP_LIST(DECLARE_METHOD)
            SIMPLIFIED_SPECULATIVE_NUMBER_UNOP_LIST(DECLARE_METHOD)
            DECLARE_METHOD(ConvertReceiver)
#undef DECLARE_METHOD

// Number binary operators.
#define DECLARE_METHOD(Name) Type Name(Type lhs, Type rhs);
            SIMPLIFIED_NUMBER_BINOP_LIST(DECLARE_METHOD)
            SIMPLIFIED_SPECULATIVE_NUMBER_BINOP_LIST(DECLARE_METHOD)
#undef DECLARE_METHOD

            // Comparison operators.
            Type SameValue(Type lhs, Type rhs);
            Type StrictEqual(Type lhs, Type rhs);

            // Check operators.
            Type CheckBounds(Type index, Type length);
            Type CheckFloat64Hole(Type type);
            Type CheckNumber(Type type);
            Type ConvertTaggedHoleToUndefined(Type type);

            Type TypeTypeGuard(const Operator* sigma_op, Type input);

            enum ComparisonOutcomeFlags {
                kComparisonTrue = 1,
                kComparisonFalse = 2,
                kComparisonUndefined = 4
            };

            Type singleton_false() const { return singleton_false_; }
            Type singleton_true() const { return singleton_true_; }
            Type singleton_the_hole() const { return singleton_the_hole_; }

        private:
            using ComparisonOutcome = base::Flags<ComparisonOutcomeFlags>;

            ComparisonOutcome Invert(ComparisonOutcome);
            Type Invert(Type);
            Type FalsifyUndefined(ComparisonOutcome);

            Type Rangify(Type);
            Type AddRanger(double lhs_min, double lhs_max, double rhs_min,
                double rhs_max);
            Type SubtractRanger(double lhs_min, double lhs_max, double rhs_min,
                double rhs_max);
            Type MultiplyRanger(double lhs_min, double lhs_max, double rhs_min,
                double rhs_max);

            Zone* zone() const { return zone_; }

            Zone* const zone_;
            TypeCache const* cache_;

            Type infinity_;
            Type minus_infinity_;
            Type singleton_NaN_string_;
            Type singleton_zero_string_;
            Type singleton_false_;
            Type singleton_true_;
            Type singleton_the_hole_;
            Type signed32ish_;
            Type unsigned32ish_;
            Type singleton_empty_string_;
            Type truish_;
            Type falsish_;
        };

    } // namespace compiler
} // namespace internal
} // namespace v8

#endif // V8_COMPILER_OPERATION_TYPER_H_
